package com.sunxd.znginxdemo2.Demo;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sunxd.znginxdemo2.Demo.annotation.LimitHandlerAnnotation;
import com.sunxd.znginxdemo2.Demo.content.BaseContent;
import com.sunxd.znginxdemo2.Demo.limit.AbstractLimitStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Description: 加载并排序
 */
@Component
@Slf4j
public class LimitDelegate<T extends BaseContent> implements ApplicationContextAware {

    private Map<String, AbstractLimitStrategy<T>> map = Maps.newHashMap();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(LimitHandlerAnnotation.class);
        Map<String, List<AbstractLimitStrategy<T>>> mapList = Maps.newHashMap();
        for (Object bean : beansWithAnnotation.values()) {
            if (bean instanceof AbstractLimitStrategy) {
                LimitHandlerAnnotation limitHandler = bean.getClass().getAnnotation(LimitHandlerAnnotation.class);
                if (mapList.containsKey(limitHandler.group())) {
                    mapList.get(limitHandler.group()).add((AbstractLimitStrategy<T>) bean);
                } else {
                    mapList.put(limitHandler.group(), Lists.newArrayList((AbstractLimitStrategy<T>) bean));
                }
            }
        }
        for (Map.Entry<String, List<AbstractLimitStrategy<T>>> next : mapList.entrySet()) {
            List<AbstractLimitStrategy<T>> limitHandlers = next.getValue();
            limitHandlers.sort(Comparator.comparing(this::findOrder));
            int size = limitHandlers.size();
            for (int i = 0; i < size; i++) {
                if (Objects.equals(i, size - 1)) {
                    limitHandlers.get(i).setNextHandler(null);
                } else {
                    limitHandlers.get(i).setNextHandler(limitHandlers.get(i + 1));
                }
            }
            map.put(next.getKey(), limitHandlers.get(0));
        }
    }
    public Boolean doExecute(T baseContent) {
        // 上层保证baseContent不为空
        if (CollectionUtils.isEmpty(baseContent.getRuleList())) {
            return Boolean.FALSE;
        }
        if (map.containsKey(baseContent.getLimitType())) {
            return map.get(baseContent.getLimitType()).doCheck(baseContent);
        }
        return Boolean.TRUE;
    }
    protected Integer findOrder(Object obj) {
        Order order = obj.getClass().getAnnotation(Order.class);
        return Objects.isNull(order) ? Integer.MAX_VALUE : order.value();
    }

}
